<?php

namespace Biz\Services\App;

use Biz\Models\App\App;
use Lumen\Logger\Logger;
use Biz\Models\Passport\Client;
use Illuminate\Support\Facades\DB;
use Biz\Constants\App\AppConstants;
use Biz\Repositories\App\AppRepository;
use Biz\Services\Passport\ClientService;
use Biz\Criteria\App\OAuthClientCriterion;
use Lumen\Core\Exceptions\BusinessException;

/**
 * UserService.
 *
 * @license [http://www.85do.com] [杭州永奥网络科技有限公司]
 * @copyright Copyright (c) 2018-2026 Hangzhou Yongao Technology Co., Ltd. All rights reserved.
 */
class AppService
{
    /**
     * @var \Lumen\Repository\Contracts\RepositoryContract
     */
    protected $repository;

    /**
     * @var ClientService
     */
    protected $clientService;

    /**
     * RepositoryController constructor.
     *
     * @param AppRepository $repository
     * @param ClientService $clientService
     */
    public function __construct(AppRepository $repository, ClientService $clientService)
    {
        $this->repository         = $repository;
        $this->clientService      = $clientService;
    }

    /**
     * Find.
     *
     * @param int $id
     *
     * @throws BusinessException
     *
     * @return App
     */
    public function find(int $id): App
    {
        $app = $this->repository->find($id);
        if (is_null($app)) {
            throw new BusinessException(trans('app.app_not_found'));
        }

        return $app;
    }

    /**
     * With find.
     *
     * @param int   $id
     * @param array $with
     *
     * @throws BusinessException
     *
     * @return App
     */
    public function findWith(int $id, $with = []): App
    {
        $site = $this->repository->with($with)->find($id);
        if (is_null($site)) {
            throw new BusinessException(trans('app.app_not_found'));
        }

        return $site;
    }

    /**
     * Create.
     *
     * @param array $data
     *
     * @throws \Exception
     *
     * @return App
     */
    public function create(array $data): App
    {
        if (! isset($data['user_id']) || empty($data['user_id'])) {
            throw new BusinessException('用户ID不可为空');
        }

        // type default
        if (! isset($data['type'])) {
            throw new BusinessException('应用类型不可为空');
        }

        // status default
        if (! isset($data['status'])) {
            $data['status'] = AppConstants::STATUS_REVIEW;
        }

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            // 创建站点OAuth客户端
            $data['redirect'] = $data['domain'];
            $client           = $this->clientService->create($data);

            // 创建站点
            $data['client_id']          = $client->id;
            $allowField                 = $this->repository->createModel()->getFillable();
            $data                       = array_only($data, $allowField);
            /** @var App $app */
            $app = $this->repository->create($data);
            if (! $app) {
                throw new BusinessException(trans('app.app_create_fail'));
            }
            $app->setClient($client);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return $app;
    }

    /**
     * Delete.
     *
     * @param int $id
     *
     * @throws \Exception
     *
     * @return bool
     */
    public function delete(int $id): bool
    {
        $app = $this->find($id);

        // 1) Start Transaction
        DB::beginTransaction();
        try {
            $this->clientService->delete($app->client_id);

            $this->repository->delete($id);

            // 2) Commit Transaction
            DB::commit();
        } catch (\Exception $e) {
            // 3) Rollback Transaction
            DB::rollback();
            // 4) Log Transaction
            Logger::error(__CLASS__, __FUNCTION__, $e);
            // 5) Throw Exception
            throw $e;
        }

        return true;
    }

    /**
     * Find By OAuth Client.
     *
     * @param Client $client
     *
     * @throws BusinessException
     *
     * @return App
     */
    public function getAppByOAuthClient(Client $client): App
    {
        $app = $this->repository
            ->pushCriterion(new OAuthClientCriterion($client))
            ->findFirst();
        if (is_null($app)) {
            throw new BusinessException(trans('app.app_not_found'));
        }

        return $app;
    }
}
